﻿#region Using Directives

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Reflection;
    using System.Text;

    using Csla;
    using Csla.Core;
    using Csla.Data;
    using Csla.Reflection;
    using Csla.Security;
    using Csla.Server;

    using MarketPulse.DataAccess;
    using MarketPulse.Reporting.Core;
    using MarketPulse.Reporting.Core.Criteria;

#endregion

namespace MarketPulse.DataAccess.Factory
{
    /// <summary>
    /// Abstracts the data access for the Security away from the Security Business Objects.
    /// </summary>
    public class ReportingVisitFactory : ObjectFactory
    {

        #region Member Variables

            /// <summary>Property that stores the name of the class.</summary>
            private static readonly Type mClass = MethodBase.GetCurrentMethod().DeclaringType;

            /// <summary>Property that stores the log4net logger for this class.</summary>
            private static readonly log4net.ILog mLog = log4net.LogManager.GetLogger(mClass);

        #endregion

        #region Methods

            #region Fetch Methods

                #region ReportingVisitInfoList

                    /// <summary>
                    /// Method used to fetch a list of read-only ReportingVisitInfo objects.      
                    /// </summary>
                    /// <param name="criteria">The criteria object holding the values used to retrieve the list</param>
                    /// <returns>An read-only list of ReportingVisitInfo objects retrieved from the database</returns>
                    public ReportingVisitInfoList FetchInfoList(ClientGUIDAndBranchGUIDAndDateRangeCriteria criteria)
                    {
                        try
                        {
                            using (var productionManager = ContextManager<DataContextObjects.Production.MUM_dev>.GetManager(Database.BusinessSystem))
                            {
                                using (var reportingManager = ContextManager<DataContextObjects.Reporting.MUMReporting_dev>.GetManager(Database.ReportingSystem))
                                {
                                    var reportingVisitInfoList = (ReportingVisitInfoList)MethodCaller.CreateInstance(typeof(ReportingVisitInfoList));
                                    SetIsReadOnly(reportingVisitInfoList, false);

                                    var productionManagerSelectResult = productionManager.DataContext.UspVisitSelectByBranchGUIDAndDateRange(criteria.BranchGUID
                                                                                                                                             ,criteria.StartDateTime
                                                                                                                                             ,criteria.EndDateTime
                                                                                                                                             ,true);

                                    foreach (var result in productionManagerSelectResult)
                                    {
                                        var reportingVisitInfo = (ReportingVisitInfo)MethodCaller.CreateInstance(typeof(ReportingVisitInfo));

                                        // Load ClientGUID from criteria
                                        LoadProperty(reportingVisitInfo, ReportingVisitInfo.ClientGUIDProperty, criteria.ClientGUID);

                                        // Load GUID and base from production Visit, everything else from reporting Visit
                                        LoadProperty(reportingVisitInfo, ReportingVisitInfo.GUIDProperty, result.VisitGUID);
                                        // Common properties inherited from MarketPulseBase<Visit>
                                        LoadProperty(reportingVisitInfo, ReportingVisitInfo.ObsoleteProperty, result.Obsolete.Value);
                                        LoadProperty(reportingVisitInfo, ReportingVisitInfo.InsertDateTimeProperty, result.InsertDateTime.Value);
                                        LoadProperty(reportingVisitInfo, ReportingVisitInfo.InsertUserGUIDProperty, result.InsertUserGUID.Value);
                                        LoadProperty(reportingVisitInfo, ReportingVisitInfo.UpdateDateTimeProperty, result.UpdateDateTime.Value);
                                        LoadProperty(reportingVisitInfo, ReportingVisitInfo.UpdateUserGUIDProperty, result.UpdateUserGUID.Value);

                                        // TODO: Add/Update 'Published' parameter.
                                        var reportingManagerSelect = reportingManager.DataContext.UspReportingVisitSelectByClientGUIDAndVisitGUID(criteria.ClientGUID, result.VisitGUID, criteria.Language, false);

                                        // TODO: Data is dirty.. something to be done about it?
                                        if (reportingManagerSelect == null) continue;

                                        ReportingQuestionInfo lastReportingQuestionInfo = null;

                                        foreach (var reportingManagerSelectResult in reportingManagerSelect)
                                        {
                                            // If this is the first iteration of this visit
                                            if (!reportingVisitInfo.ID.HasValue)
                                            {
                                                // Other properties                    
                                                LoadProperty(reportingVisitInfo, ReportingVisitInfo.VisitIDProperty, reportingManagerSelectResult.VisitID);
                                                LoadProperty(reportingVisitInfo, ReportingVisitInfo.VisitVersionIDProperty, reportingManagerSelectResult.VisitVersionID.Value);
                                                LoadProperty(reportingVisitInfo, ReportingVisitInfo.BranchGUIDProperty, result.BranchGUID.Value);
                                                LoadProperty(reportingVisitInfo, ReportingVisitInfo.RoundGUIDProperty, reportingManagerSelectResult.RoundGUID);
                                                LoadProperty(reportingVisitInfo, ReportingVisitInfo.UserGUIDProperty, reportingManagerSelectResult.UserGUID);
                                                LoadProperty(reportingVisitInfo, ReportingVisitInfo.ComponentGUIDProperty, reportingManagerSelectResult.ComponentGUID);
                                                LoadProperty(reportingVisitInfo, ReportingVisitInfo.CountryGUIDProperty, reportingManagerSelectResult.CountryGUID);
                                                LoadProperty(reportingVisitInfo, ReportingVisitInfo.LanguageGUIDProperty, reportingManagerSelectResult.LanguageGUID);
                                                LoadProperty(reportingVisitInfo, ReportingVisitInfo.LabelProperty, reportingManagerSelectResult.VisitLabel);
                                                LoadProperty(reportingVisitInfo, ReportingVisitInfo.PossibleScoreProperty, reportingManagerSelectResult.PossibleScore.Value);
                                                LoadProperty(reportingVisitInfo, ReportingVisitInfo.ActualScoreProperty, reportingManagerSelectResult.ActualScore.Value);
                                                LoadProperty(reportingVisitInfo, ReportingVisitInfo.PublishedProperty, reportingManagerSelectResult.Published.Value);
                                                LoadProperty(reportingVisitInfo, ReportingVisitInfo.TransferredDateTimeProperty, reportingManagerSelectResult.TransferDateTime);
                                                LoadProperty(reportingVisitInfo, ReportingVisitInfo.ValidStartDateTimeProperty, reportingManagerSelectResult.ValidStartDateTime);
                                                LoadProperty(reportingVisitInfo, ReportingVisitInfo.ValidEndDateTimeProperty, reportingManagerSelectResult.ValidEndDateTime);
                                                LoadProperty(reportingVisitInfo, ReportingVisitInfo.PlannedDateTimeProperty, reportingManagerSelectResult.PlannedDateTime);
                                                LoadProperty(reportingVisitInfo, ReportingVisitInfo.ActualStartDateTimeProperty, reportingManagerSelectResult.ActualStartDateTime);
                                                LoadProperty(reportingVisitInfo, ReportingVisitInfo.ActualEndDateTimeProperty, reportingManagerSelectResult.ActualEndDateTime);

                                                // Populate the first question row.
                                                var reportingQuestionInfoList = (ReportingQuestionInfoList)MethodCaller.CreateInstance(typeof(ReportingQuestionInfoList));
                                                SetIsReadOnly(reportingQuestionInfoList, false);

                                                var reportingQuestionInfo = (ReportingQuestionInfo)MethodCaller.CreateInstance(typeof(ReportingQuestionInfo));
                                                // Base properties
                                                LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.GUIDProperty, reportingManagerSelectResult.QuestionGUID.Value);
                                                // Extended properties
                                                LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.IDProperty, reportingManagerSelectResult.QuestionID.Value);
                                                LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.ClientGUIDProperty, criteria.ClientGUID);
                                                LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.VisitGUIDProperty, reportingManagerSelectResult.VisitGUID.Value);
                                                LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.CategoryGUIDProperty, reportingManagerSelectResult.CategoryGUID.Value);
                                                LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.CategoryOrderProperty, reportingManagerSelectResult.CategoryOrder.Value);
                                                LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.CategoryTitleProperty, reportingManagerSelectResult.CategoryTitle);
                                                LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.DisplayNumberProperty, reportingManagerSelectResult.DisplayNumber);
                                                LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.NumberProperty, reportingManagerSelectResult.QuestionNumber);
                                                //LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.TextProperty, reportingManagerSelectResult.QuestionText);
                                                LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.TypeProperty, reportingManagerSelectResult.QuestionType);
                                                //LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.StandardProperty, reportingManagerSelectResult.QuestionStandard);
                                                //LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.ShopperNoteProperty, reportingManagerSelectResult.ShopperNote);
                                                //LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.QANoteProperty, reportingManagerSelectResult.QANote);
                                                LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.PossibleScoreProperty, reportingManagerSelectResult.QuestionPossibleScore.Value);
                                                LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.ActualScoreProperty, reportingManagerSelectResult.QuestionActualScore.Value);
                                                LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.TransferDateTimeProperty, reportingManagerSelectResult.TransferDateTime);

                                                // Initalise the question references property.
                                                var questionReferences = new List<string>();
                                                if (!String.IsNullOrEmpty(reportingManagerSelectResult.QuestionReferenceTypeShortName))
                                                {
                                                    questionReferences.Add(reportingManagerSelectResult.QuestionReferenceTypeShortName);
                                                }
                                                LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.ReferencesProperty, questionReferences);

                                                // Let Csla know this object has changed
                                                MarkOld(reportingQuestionInfo);

                                                // Add the question to the collection
                                                reportingQuestionInfoList.Add(reportingQuestionInfo);

                                                // Save this question for appending to later.
                                                lastReportingQuestionInfo = reportingQuestionInfo;

                                                // Set the ReportingQuestionInfoList to read-only now
                                                SetIsReadOnly(reportingQuestionInfoList, true);

                                                // Set ReportingQuestionInfoList onto the ReportingVisitInfoList
                                                LoadProperty(reportingVisitInfo, ReportingVisitInfo.ReportingQuestionsProperty, reportingQuestionInfoList);
                                            }
                                            else
                                            {
                                                // Not the first iteration of this visit, add/update question as required.
                                                if (lastReportingQuestionInfo == null || !lastReportingQuestionInfo.GUID.Value.Equals(reportingManagerSelectResult.QuestionGUID.Value))
                                                {
                                                    // Add new question
                                                    var reportingQuestionInfo = (ReportingQuestionInfo)MethodCaller.CreateInstance(typeof(ReportingQuestionInfo));
                                                    // Base properties
                                                    LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.GUIDProperty, reportingManagerSelectResult.QuestionGUID.Value);
                                                    // Extended properties
                                                    LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.IDProperty, reportingManagerSelectResult.QuestionID.Value);
                                                    LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.ClientGUIDProperty, criteria.ClientGUID);
                                                    LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.VisitGUIDProperty, reportingManagerSelectResult.VisitGUID.Value);
                                                    LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.CategoryGUIDProperty, reportingManagerSelectResult.CategoryGUID.Value);
                                                    LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.CategoryOrderProperty, reportingManagerSelectResult.CategoryOrder.Value);
                                                    LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.CategoryTitleProperty, reportingManagerSelectResult.CategoryTitle);
                                                    LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.DisplayNumberProperty, reportingManagerSelectResult.DisplayNumber);
                                                    LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.NumberProperty, reportingManagerSelectResult.QuestionNumber);
                                                    //LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.TextProperty, reportingManagerSelectResult.QuestionText);
                                                    LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.TypeProperty, reportingManagerSelectResult.QuestionType);
                                                    //LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.StandardProperty, reportingManagerSelectResult.QuestionStandard);
                                                    //LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.ShopperNoteProperty, reportingManagerSelectResult.ShopperNote);
                                                    //LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.QANoteProperty, reportingManagerSelectResult.QANote);
                                                    LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.PossibleScoreProperty, reportingManagerSelectResult.QuestionPossibleScore.Value);
                                                    LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.ActualScoreProperty, reportingManagerSelectResult.QuestionActualScore.Value);
                                                    LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.TransferDateTimeProperty, reportingManagerSelectResult.TransferDateTime);

                                                    // Initalise the question references property.
                                                    var questionReferences = new List<string>();
                                                    if (!String.IsNullOrEmpty(reportingManagerSelectResult.QuestionReferenceTypeShortName))
                                                    {
                                                        questionReferences.Add(reportingManagerSelectResult.QuestionReferenceTypeShortName);
                                                    }
                                                    LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.ReferencesProperty, questionReferences);

                                                    // Let Csla know this object has changed
                                                    MarkOld(reportingQuestionInfo);

                                                    // Use our existing question collection and set it as read-only
                                                    SetIsReadOnly(reportingVisitInfo.ReportingQuestions, false);

                                                    // Append the new question
                                                    reportingVisitInfo.ReportingQuestions.Add(reportingQuestionInfo);

                                                    // Set the question collection back to read only
                                                    SetIsReadOnly(reportingVisitInfo.ReportingQuestions, true);
                                                }
                                                else
                                                {
                                                    // Update current question
                                                    if (!String.IsNullOrEmpty(reportingManagerSelectResult.QuestionReferenceTypeShortName))
                                                    {
                                                        // We have new references to append to the existing question.
                                                        lastReportingQuestionInfo.References.Add(reportingManagerSelectResult.QuestionReferenceTypeShortName);

                                                        // Let Csla know this object has changed.
                                                        MarkOld(lastReportingQuestionInfo);
                                                    }
                                                }
                                            }
                                        }

                                        // Let Csla this object has changed since instantiation.
                                        MarkOld(reportingVisitInfo);

                                        // Add the object to the list
                                        reportingVisitInfoList.Add(reportingVisitInfo);
                                    }

                                    MarkOld(reportingVisitInfoList);

                                    return reportingVisitInfoList;
                                }
                            }
                        }
                        catch (InvalidOperationException ioe)
                        {
                            //TODO log exception appropriately before re throwing
                            throw ioe;
                        }
                        catch (Exception ex)
                        {
                            throw ex;
                        }
                    }

                    /// <summary>
                    /// Method used to fetch a list of read-only ReportingVisitInfo objects.      
                    /// </summary>
                    /// <param name="criteria">The criteria object holding the values used to retrieve the list</param>
                    /// <returns>An read-only list of ReportingVisitInfo objects retrieved from the database</returns>
                    public ReportingVisitInfoList FetchInfoList(ResultsCriteria criteria)
                    {
                        try
                        {
                            using (var productionManager = ContextManager<DataContextObjects.Production.MUM_dev>.GetManager(Database.BusinessSystem))
                            {
                                using (var reportingManager = ContextManager<DataContextObjects.Reporting.MUMReporting_dev>.GetManager(Database.ReportingSystem))
                                {
                                    var reportingVisitInfoList = (ReportingVisitInfoList)MethodCaller.CreateInstance(typeof(ReportingVisitInfoList));
                                    SetIsReadOnly(reportingVisitInfoList, false);

                                    // If a BranchGUID is set, override any ReportingLevel chosen.
                                    if (criteria.BranchGUID.HasValue)
                                    {
                                        // Get Visits by BranchGUID
                                        var branchSelectResult = productionManager.DataContext.UspVisitSelectByDateRangeAndBranchGUIDList(criteria.DataStartDateTime
                                                                                                                                         ,criteria.DataEndDateTime
                                                                                                                                         ,criteria.BranchGUID.Value.ToString());

                                        foreach (var result in branchSelectResult)
                                        {
                                            // Check to make sure that our Company reporting level procedure hasn't already added this visit.
                                            if (reportingVisitInfoList.FirstOrDefault(v => v.GUID.Value.Equals(result.VisitGUID.Value)) != null) continue;

                                            var reportingVisitInfo = (ReportingVisitInfo)MethodCaller.CreateInstance(typeof(ReportingVisitInfo));

                                            // Load ClientGUID from criteria
                                            LoadProperty(reportingVisitInfo, ReportingVisitInfo.ClientGUIDProperty, criteria.ClientGUID);

                                            // Load GUID and base from production Visit, everything else from reporting Visit
                                            LoadProperty(reportingVisitInfo, ReportingVisitInfo.GUIDProperty, result.VisitGUID);
                                            LoadProperty(reportingVisitInfo, ReportingVisitInfo.BranchGUIDProperty, result.BranchGUID.Value);
                                            LoadProperty(reportingVisitInfo, ReportingVisitInfo.EffectiveRoundStartDateTimeProperty, (SmartDate)result.EffectiveStartDateTime.Value);
                                            LoadProperty(reportingVisitInfo, ReportingVisitInfo.EffectiveRoundEndDateTimeProperty, (SmartDate)result.EffectiveEndDateTime.Value);
                                            LoadProperty(reportingVisitInfo, ReportingVisitInfo.ComponentLabelProperty, result.ComponentLabel);
                                            // Common properties inherited from MarketPulseBase<Visit>
                                            LoadProperty(reportingVisitInfo, ReportingVisitInfo.ObsoleteProperty, result.Obsolete.Value);
                                            LoadProperty(reportingVisitInfo, ReportingVisitInfo.InsertDateTimeProperty, result.InsertDateTime.Value);
                                            LoadProperty(reportingVisitInfo, ReportingVisitInfo.InsertUserGUIDProperty, result.InsertUserGUID.Value);
                                            LoadProperty(reportingVisitInfo, ReportingVisitInfo.UpdateDateTimeProperty, result.UpdateDateTime.Value);
                                            LoadProperty(reportingVisitInfo, ReportingVisitInfo.UpdateUserGUIDProperty, result.UpdateUserGUID.Value);

                                            // Let Csla know that this object has changed
                                            MarkOld(reportingVisitInfo);

                                            // Add this ReportingVisitInfo object to the ReportingVisitInfoList
                                            reportingVisitInfoList.Add(reportingVisitInfo);
                                        }
                                    }
                                    else
                                    {

                                        // Get Visits by ReportingLevel (Company)
                                        var companySelectResult = productionManager.DataContext.UspVisitSelectByDateRangeAndCompanyGUIDList(criteria.DataStartDateTime
                                                                                                                                            ,criteria.DataEndDateTime
                                                                                                                                            ,String.Join(",", criteria.ReportingLevels.SelectedCompanies));

                                        foreach (var result in companySelectResult)
                                        {
                                            var reportingVisitInfo = (ReportingVisitInfo)MethodCaller.CreateInstance(typeof(ReportingVisitInfo));

                                            // Load ClientGUID from criteria
                                            LoadProperty(reportingVisitInfo, ReportingVisitInfo.ClientGUIDProperty, criteria.ClientGUID);

                                            // Load GUID and base from production Visit, everything else from reporting Visit
                                            LoadProperty(reportingVisitInfo, ReportingVisitInfo.GUIDProperty, result.VisitGUID);
                                            LoadProperty(reportingVisitInfo, ReportingVisitInfo.BranchGUIDProperty, result.BranchGUID.Value);
                                            LoadProperty(reportingVisitInfo, ReportingVisitInfo.EffectiveRoundStartDateTimeProperty, (SmartDate)result.EffectiveStartDateTime.Value);
                                            LoadProperty(reportingVisitInfo, ReportingVisitInfo.EffectiveRoundEndDateTimeProperty, (SmartDate)result.EffectiveEndDateTime.Value);
                                            LoadProperty(reportingVisitInfo, ReportingVisitInfo.ComponentLabelProperty, result.ComponentLabel);
                                            // Common properties inherited from MarketPulseBase<Visit>
                                            LoadProperty(reportingVisitInfo, ReportingVisitInfo.ObsoleteProperty, result.Obsolete.Value);
                                            LoadProperty(reportingVisitInfo, ReportingVisitInfo.InsertDateTimeProperty, result.InsertDateTime.Value);
                                            LoadProperty(reportingVisitInfo, ReportingVisitInfo.InsertUserGUIDProperty, result.InsertUserGUID.Value);
                                            LoadProperty(reportingVisitInfo, ReportingVisitInfo.UpdateDateTimeProperty, result.UpdateDateTime.Value);
                                            LoadProperty(reportingVisitInfo, ReportingVisitInfo.UpdateUserGUIDProperty, result.UpdateUserGUID.Value);

                                            // Let Csla know that this object has changed
                                            MarkOld(reportingVisitInfo);

                                            // Add this ReportingVisitInfo object to the ReportingVisitInfoList
                                            reportingVisitInfoList.Add(reportingVisitInfo);
                                        }

                                        // Get Visits by ReportingLevel (Branch)
                                        var branchSelectResult = productionManager.DataContext.UspVisitSelectByDateRangeAndBranchGUIDList(criteria.DataStartDateTime
                                                                                                                                         ,criteria.DataEndDateTime
                                                                                                                                         ,String.Join(",", criteria.ReportingLevels.SelectedBranches));

                                        foreach (var result in branchSelectResult)
                                        {
                                            // Check to make sure that our Company reporting level procedure hasn't already added this visit.
                                            if (reportingVisitInfoList.FirstOrDefault(v => v.GUID.Value.Equals(result.VisitGUID.Value)) != null) continue;

                                            var reportingVisitInfo = (ReportingVisitInfo)MethodCaller.CreateInstance(typeof(ReportingVisitInfo));

                                            // Load ClientGUID from criteria
                                            LoadProperty(reportingVisitInfo, ReportingVisitInfo.ClientGUIDProperty, criteria.ClientGUID);

                                            // Load GUID and base from production Visit, everything else from reporting Visit
                                            LoadProperty(reportingVisitInfo, ReportingVisitInfo.GUIDProperty, result.VisitGUID);
                                            LoadProperty(reportingVisitInfo, ReportingVisitInfo.BranchGUIDProperty, result.BranchGUID.Value);
                                            LoadProperty(reportingVisitInfo, ReportingVisitInfo.EffectiveRoundStartDateTimeProperty, (SmartDate)result.EffectiveStartDateTime.Value);
                                            LoadProperty(reportingVisitInfo, ReportingVisitInfo.EffectiveRoundEndDateTimeProperty, (SmartDate)result.EffectiveEndDateTime.Value);
                                            LoadProperty(reportingVisitInfo, ReportingVisitInfo.ComponentLabelProperty, result.ComponentLabel);
                                            // Common properties inherited from MarketPulseBase<Visit>
                                            LoadProperty(reportingVisitInfo, ReportingVisitInfo.ObsoleteProperty, result.Obsolete.Value);
                                            LoadProperty(reportingVisitInfo, ReportingVisitInfo.InsertDateTimeProperty, result.InsertDateTime.Value);
                                            LoadProperty(reportingVisitInfo, ReportingVisitInfo.InsertUserGUIDProperty, result.InsertUserGUID.Value);
                                            LoadProperty(reportingVisitInfo, ReportingVisitInfo.UpdateDateTimeProperty, result.UpdateDateTime.Value);
                                            LoadProperty(reportingVisitInfo, ReportingVisitInfo.UpdateUserGUIDProperty, result.UpdateUserGUID.Value);

                                            // Let Csla know that this object has changed
                                            MarkOld(reportingVisitInfo);

                                            // Add this ReportingVisitInfo object to the ReportingVisitInfoList
                                            reportingVisitInfoList.Add(reportingVisitInfo);
                                        }
                                    }

                                    foreach(var reportingVisitInfo in reportingVisitInfoList)
                                    {
                                        // TODO: Add/Update 'Published' parameter.
                                        var reportingManagerSelect = reportingManager.DataContext.UspReportingVisitSelectByClientGUIDAndVisitGUID(criteria.ClientGUID, reportingVisitInfo.GUID.Value, criteria.Language, false);

                                        // TODO: Data is dirty.. something to be done about it?
                                        if (reportingManagerSelect == null) continue;

                                        ReportingQuestionInfo lastReportingQuestionInfo = null;

                                        foreach (var reportingManagerSelectResult in reportingManagerSelect)
                                        {
                                            // If this is the first iteration of this visit
                                            if (!reportingVisitInfo.ID.HasValue)
                                            {
                                                // Other properties
                                                LoadProperty(reportingVisitInfo, ReportingVisitInfo.VisitIDProperty, reportingManagerSelectResult.VisitID);
                                                LoadProperty(reportingVisitInfo, ReportingVisitInfo.VisitVersionIDProperty, reportingManagerSelectResult.VisitVersionID.Value);
                                                LoadProperty(reportingVisitInfo, ReportingVisitInfo.RoundGUIDProperty, reportingManagerSelectResult.RoundGUID);
                                                LoadProperty(reportingVisitInfo, ReportingVisitInfo.UserGUIDProperty, reportingManagerSelectResult.UserGUID);
                                                LoadProperty(reportingVisitInfo, ReportingVisitInfo.ComponentGUIDProperty, reportingManagerSelectResult.ComponentGUID);
                                                LoadProperty(reportingVisitInfo, ReportingVisitInfo.CountryGUIDProperty, reportingManagerSelectResult.CountryGUID);
                                                LoadProperty(reportingVisitInfo, ReportingVisitInfo.LanguageGUIDProperty, reportingManagerSelectResult.LanguageGUID);
                                                LoadProperty(reportingVisitInfo, ReportingVisitInfo.LabelProperty, reportingManagerSelectResult.VisitLabel);
                                                LoadProperty(reportingVisitInfo, ReportingVisitInfo.PossibleScoreProperty, reportingManagerSelectResult.PossibleScore.Value);
                                                LoadProperty(reportingVisitInfo, ReportingVisitInfo.ActualScoreProperty, reportingManagerSelectResult.ActualScore.Value);
                                                LoadProperty(reportingVisitInfo, ReportingVisitInfo.PublishedProperty, reportingManagerSelectResult.Published.Value);
                                                LoadProperty(reportingVisitInfo, ReportingVisitInfo.TransferredDateTimeProperty, reportingManagerSelectResult.TransferDateTime);
                                                LoadProperty(reportingVisitInfo, ReportingVisitInfo.ValidStartDateTimeProperty, reportingManagerSelectResult.ValidStartDateTime);
                                                LoadProperty(reportingVisitInfo, ReportingVisitInfo.ValidEndDateTimeProperty, reportingManagerSelectResult.ValidEndDateTime);
                                                LoadProperty(reportingVisitInfo, ReportingVisitInfo.PlannedDateTimeProperty, reportingManagerSelectResult.PlannedDateTime);
                                                LoadProperty(reportingVisitInfo, ReportingVisitInfo.ActualStartDateTimeProperty, reportingManagerSelectResult.ActualStartDateTime);
                                                LoadProperty(reportingVisitInfo, ReportingVisitInfo.ActualEndDateTimeProperty, reportingManagerSelectResult.ActualEndDateTime);

                                                // Populate the first question row.
                                                var reportingQuestionInfoList = (ReportingQuestionInfoList)MethodCaller.CreateInstance(typeof(ReportingQuestionInfoList));
                                                SetIsReadOnly(reportingQuestionInfoList, false);

                                                var reportingQuestionInfo = (ReportingQuestionInfo)MethodCaller.CreateInstance(typeof(ReportingQuestionInfo));
                                                // Base properties
                                                LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.GUIDProperty, reportingManagerSelectResult.QuestionGUID.Value);
                                                // Extended properties
                                                LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.IDProperty, reportingManagerSelectResult.QuestionID.Value);
                                                LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.ClientGUIDProperty, criteria.ClientGUID);
                                                LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.VisitGUIDProperty, reportingManagerSelectResult.VisitGUID.Value);
                                                LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.CategoryGUIDProperty, reportingManagerSelectResult.CategoryGUID.Value);
                                                LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.CategoryOrderProperty, reportingManagerSelectResult.CategoryOrder.Value);
                                                LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.CategoryTitleProperty, reportingManagerSelectResult.CategoryTitle);
                                                LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.DisplayNumberProperty, reportingManagerSelectResult.DisplayNumber);
                                                //LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.NumberProperty, reportingManagerSelectResult.QuestionNumber);
                                                //LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.TextProperty, reportingManagerSelectResult.QuestionText);
                                                LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.TypeProperty, reportingManagerSelectResult.QuestionType);
                                                //LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.StandardProperty, reportingManagerSelectResult.QuestionStandard);
                                                //LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.ShopperNoteProperty, reportingManage    rSelectResult.ShopperNote);
                                                //LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.QANoteProperty, reportingManagerSelectResult.QANote);
                                                LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.PossibleScoreProperty, reportingManagerSelectResult.QuestionPossibleScore.Value);
                                                LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.ActualScoreProperty, reportingManagerSelectResult.QuestionActualScore.Value);
                                                LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.TransferDateTimeProperty, reportingManagerSelectResult.TransferDateTime);

                                                // Initalise the question references property.
                                                var questionReferences = new List<string>();
                                                if (!String.IsNullOrEmpty(reportingManagerSelectResult.QuestionReferenceTypeShortName))
                                                {
                                                    questionReferences.Add(reportingManagerSelectResult.QuestionReferenceTypeShortName);
                                                }
                                                LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.ReferencesProperty, questionReferences);

                                                // Let Csla know this object has changed
                                                MarkOld(reportingQuestionInfo);

                                                // Add the question to the collection
                                                reportingQuestionInfoList.Add(reportingQuestionInfo);

                                                // Save this question for appending to later.
                                                lastReportingQuestionInfo = reportingQuestionInfo;

                                                // Set the ReportingQuestionInfoList to read-only now
                                                SetIsReadOnly(reportingQuestionInfoList, true);

                                                // Set ReportingQuestionInfoList onto the ReportingVisitInfoList
                                                LoadProperty(reportingVisitInfo, ReportingVisitInfo.ReportingQuestionsProperty, reportingQuestionInfoList);
                                            }
                                            else
                                            {
                                                // Not the first iteration of this visit, add/update question as required.
                                                if (lastReportingQuestionInfo == null || !lastReportingQuestionInfo.GUID.Value.Equals(reportingManagerSelectResult.QuestionGUID.Value))
                                                {
                                                    // Add new question
                                                    var reportingQuestionInfo = (ReportingQuestionInfo)MethodCaller.CreateInstance(typeof(ReportingQuestionInfo));
                                                    // Base properties
                                                    LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.GUIDProperty, reportingManagerSelectResult.QuestionGUID.Value);
                                                    // Extended properties
                                                    LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.IDProperty, reportingManagerSelectResult.QuestionID.Value);
                                                    LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.ClientGUIDProperty, criteria.ClientGUID);
                                                    LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.VisitGUIDProperty, reportingManagerSelectResult.VisitGUID.Value);
                                                    LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.CategoryGUIDProperty, reportingManagerSelectResult.CategoryGUID.Value);
                                                    LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.CategoryOrderProperty, reportingManagerSelectResult.CategoryOrder.Value);
                                                    LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.CategoryTitleProperty, reportingManagerSelectResult.CategoryTitle);
                                                    LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.DisplayNumberProperty, reportingManagerSelectResult.DisplayNumber);
                                                    LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.NumberProperty, reportingManagerSelectResult.QuestionNumber);
                                                    //LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.TextProperty, reportingManagerSelectResult.QuestionText);
                                                    LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.TypeProperty, reportingManagerSelectResult.QuestionType);
                                                    //LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.StandardProperty, reportingManagerSelectResult.QuestionStandard);
                                                    //LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.ShopperNoteProperty, reportingManagerSelectResult.ShopperNote);
                                                    //LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.QANoteProperty, reportingManagerSelectResult.QANote);
                                                    LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.PossibleScoreProperty, reportingManagerSelectResult.QuestionPossibleScore.Value);
                                                    LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.ActualScoreProperty, reportingManagerSelectResult.QuestionActualScore.Value);
                                                    LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.TransferDateTimeProperty, reportingManagerSelectResult.TransferDateTime);

                                  
                                                    // Initalise the question references property.
                                                    var questionReferences = new List<string>();
                                                    if (!String.IsNullOrEmpty(reportingManagerSelectResult.QuestionReferenceTypeShortName))
                                                    {
                                                        questionReferences.Add(reportingManagerSelectResult.QuestionReferenceTypeShortName);
                                                    }
                                                    LoadProperty(reportingQuestionInfo, ReportingQuestionInfo.ReferencesProperty, questionReferences);

                                                    // Let Csla know this object has changed
                                                    MarkOld(reportingQuestionInfo);

                                                    // Use our existing question collection and set it as read-only
                                                    SetIsReadOnly(reportingVisitInfo.ReportingQuestions, false);

                                                    // Append the new question
                                                    reportingVisitInfo.ReportingQuestions.Add(reportingQuestionInfo);

                                                    // Set the question collection back to read only
                                                    SetIsReadOnly(reportingVisitInfo.ReportingQuestions, true);

                                                    lastReportingQuestionInfo = reportingQuestionInfo;
                                                }
                                                else
                                                {
                                                    // Update current question
                                                    if (!String.IsNullOrEmpty(reportingManagerSelectResult.QuestionReferenceTypeShortName))
                                                    {
                                                        // We have new references to append to the existing question.
                                                        lastReportingQuestionInfo.References.Add(reportingManagerSelectResult.QuestionReferenceTypeShortName);

                                                        // Let Csla know this object has changed.
                                                        MarkOld(lastReportingQuestionInfo);
                                                    }
                                                }
                                            }
                                        }

                                        // Let Csla this object has changed since instantiation.
                                        MarkOld(reportingVisitInfo);
                                    }

                                    // Let Csla know this object has changed since instantiation.
                                    MarkOld(reportingVisitInfoList);

                                    return reportingVisitInfoList;
                                }
                            }
                        }
                        catch (InvalidOperationException ioe)
                        {
                            //TODO log exception appropriately before re throwing
                            throw ioe;
                        }
                        catch (Exception ex)
                        {
                            throw ex;
                        }
                    }

                #endregion

            #endregion

        #endregion
    }
}
